home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 365_02 / tmp.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  17KB  |  760 lines

  1. /* tmp.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains functions which create & readback a TMPFILE */
  12.  
  13.  
  14. #include "config.h"
  15. #include "vi.h"
  16. #if TOS
  17. # include <stat.h>
  18. #else
  19. # if OSK
  20. #  include "osk.h"
  21. # else
  22. #  if AMIGA
  23. #   include "amistat.h"
  24. #  else
  25. #   include <sys/stat.h>
  26. #  endif
  27. # endif
  28. #endif
  29. #if TURBOC
  30. # include <process.h>
  31. #endif
  32.  
  33. #ifndef NO_MODELINES
  34. static void do_modelines(l, stop)
  35.     long    l;    /* line number to start at */
  36.     long    stop;    /* line number to stop at */
  37. {
  38.     char    *str;    /* used to scan through the line */
  39.     char    *start;    /* points to the start of the line */
  40.     char    buf[80];
  41.  
  42.     /* if modelines are disabled, then do nothing */
  43.     if (!*o_modelines)
  44.     {
  45.         return;
  46.     }
  47.  
  48.     /* for each line... */
  49.     for (; l <= stop; l++)
  50.     {
  51.         /* for each position in the line.. */
  52.         for (str = fetchline(l); *str; str++)
  53.         {
  54.             /* if it is the start of a modeline command... */
  55.             if ((str[0] == 'e' && str[1] == 'x'
  56.               || str[0] == 'v' && str[1] == 'i')
  57.               && str[2] == ':')
  58.             {
  59.                 start = str += 3;
  60.  
  61.                 /* find the end */
  62.                 for (str = start + strlen(start); *--str != ':'; )
  63.                 {
  64.                 }
  65.  
  66.                 /* if it is a well-formed modeline, execute it */
  67.                 if (str > start && str - start < sizeof buf)
  68.                 {
  69.                     strncpy(buf, start, (int)(str - start));
  70.                     exstring(buf, str - start, '\\');
  71.                     break;
  72.                 }
  73.             }
  74.         }
  75.     }
  76. }
  77. #endif
  78.  
  79.  
  80. /* The FAIL() macro prints an error message and then exits. */
  81. #define FAIL(why,arg)    mode = MODE_EX; msg(why, arg); endwin(); exit(9)
  82.  
  83. /* This is the name of the temp file */
  84. static char    tmpname[80];
  85.  
  86. /* This function creates the temp file and copies the original file into it.
  87.  * Returns if successful, or stops execution if it fails.
  88.  */
  89. int tmpstart(filename)
  90.     char        *filename; /* name of the original file */
  91. {
  92.     int        origfd;    /* fd used for reading the original file */
  93.     struct stat    statb;    /* stat buffer, used to examine inode */
  94.     REG BLK        *this;    /* pointer to the current block buffer */
  95.     REG BLK        *next;    /* pointer to the next block buffer */
  96.     int        inbuf;    /* number of characters in a buffer */
  97.     int        nread;    /* number of bytes read */
  98.     REG int        j, k;
  99.     int        i;
  100.     long        nbytes;
  101.  
  102.     /* switching to a different file certainly counts as a change */
  103.     changes++;
  104.     redraw(MARK_UNSET, FALSE);
  105.  
  106.     /* open the original file for reading */
  107.     *origname = '\0';
  108.     if (filename && *filename)
  109.     {
  110.         strcpy(origname, filename);
  111.         origfd = open(origname, O_RDONLY);
  112.         if (origfd < 0 && errno != ENOENT)
  113.         {
  114.             msg("Can't open \"%s\"", origname);
  115.             return tmpstart("");
  116.         }
  117.         if (origfd >= 0)
  118.         {
  119.             if (stat(origname, &statb) < 0)
  120.             {
  121.                 FAIL("Can't stat \"%s\"", origname);
  122.             }
  123. #if TOS
  124.             if (origfd >= 0 && (statb.st_mode & S_IJDIR))
  125. #else
  126. # if OSK
  127.             if (origfd >= 0 && (statb.st_mode & S_IFDIR))
  128. # else
  129.             if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG)
  130. # endif
  131. #endif
  132.             {
  133.                 msg("\"%s\" is not a regular file", origname);
  134.                 return tmpstart("");
  135.             }
  136.         }
  137.         else
  138.         {
  139.             stat(".", &statb);
  140.         }
  141.         if (origfd >= 0)
  142.         {
  143.             origtime = statb.st_mtime;
  144. #if OSK
  145.             if (*o_readonly || !(statb.st_mode &
  146.                   ((getuid() >> 16) == 0 ? S_IOWRITE | S_IWRITE :
  147.                   ((statb.st_gid != (getuid() >> 16) ? S_IOWRITE : S_IWRITE)))))
  148. #endif
  149. #if AMIGA || MSDOS || (TOS && defined(__GNUC__))
  150.             if (*o_readonly || !(statb.st_mode & S_IWRITE))
  151. #endif
  152. #if TOS && !defined(__GNUC__)
  153.             if (*o_readonly || (statb.st_mode & S_IJRON))
  154. #endif
  155. #if ANY_UNIX
  156.             if (*o_readonly || !(statb.st_mode &
  157.                   ((geteuid() == 0) ? 0222 :
  158.                   ((statb.st_uid != geteuid() ? 0022 : 0200)))))
  159. #endif
  160. #if VMS
  161.             if (*o_readonly)
  162. #endif
  163.             {
  164.                 setflag(file, READONLY);
  165.             }
  166.         }
  167.         else
  168.         {
  169.             origtime = 0L;
  170.         }
  171.     }
  172.     else
  173.     {
  174.         setflag(file, NOFILE);
  175.         origfd = -1;
  176.         origtime = 0L;
  177.         stat(".", &statb);
  178.     }
  179.  
  180.     /* make a name for the tmp file */
  181.     tmpnum++;
  182. #if MSDOS || TOS
  183.     /* MS-Dos doesn't allow multiple slashes, but supports drives
  184.      * with current directories.
  185.      * This relies on TMPNAME beginning with "%s\\"!!!!
  186.      */
  187.     strcpy(tmpname, o_directory);
  188.     if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1]))
  189.         tmpname[i++]=SLASH;
  190.     sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum);
  191. #else
  192.     sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum);
  193. #endif
  194.  
  195.     /* make sure nobody else is editing the same file */
  196.     if (access(tmpname, 0) == 0)
  197.     {
  198.         FAIL("Temp file \"%s\" already exists?", tmpname);
  199.     }
  200.  
  201.     /* create the temp file */
  202. #if ANY_UNIX
  203.     close(creat(tmpname, 0600));        /* only we can read it */
  204. #else
  205.     close(creat(tmpname, FILEPERMS));    /* anybody body can read it, alas */
  206. #endif
  207.     tmpfd = open(tmpname, O_RDWR | O_BINARY);
  208.     if (tmpfd < 0)
  209.     {
  210.         FAIL("Can't create temp file... Does directory \"%s\" exist?", o_directory);
  211.         return 1;
  212.     }
  213.  
  214.     /* allocate space for the header in the file */
  215.     write(tmpfd, hdr.c, (unsigned)BLKSIZE);
  216.     write(tmpfd, tmpblk.c, (unsigned)BLKSIZE);
  217.  
  218. #ifndef NO_RECYCLE
  219.     /* initialize the block allocator */
  220.     /* This must already be done here, before the first attempt
  221.      * to write to the new file! GB */
  222.     garbage();
  223. #endif
  224.  
  225.     /* initialize lnum[] */
  226.     for (i = 1; i < MAXBLKS; i++)
  227.     {
  228.         lnum[i] = INFINITY;
  229.     }
  230.     lnum[0] = 0;
  231.  
  232.     /* if there is no original file, then create a 1-line file */
  233.     if (origfd < 0)
  234.     {
  235.         hdr.n[0] = 0;    /* invalid inode# denotes new file */
  236.  
  237.         this = blkget(1);     /* get the new text block */
  238.         strcpy(this->c, "\n");    /* put a line in it */
  239.  
  240.         lnum[1] = 1L;    /* block 1 ends with line 1 */
  241.         nlines = 1L;    /* there is 1 line in the file */
  242.         nbytes = 1L;
  243.  
  244.         if (*origname)
  245.         {
  246.             msg("\"%s\" [NEW FILE]  1 line, 1 char", origname);
  247.         }
  248.         else
  249.         {
  250.             msg("\"[NO FILE]\"  1 line, 1 char");
  251.         }
  252.     }
  253.     else /* there is an original file -- read it in */
  254.     {
  255.         nbytes = nlines = 0;
  256.  
  257.         /* preallocate 1 "next" buffer */
  258.         i = 1;
  259.         next = blkget(i);
  260.         inbuf = 0;
  261.  
  262.         /* loop, moving blocks from orig to tmp */
  263.         for (;;)
  264.         {
  265.             /* "next" buffer becomes "this" buffer */
  266.             this = next;
  267.  
  268.             /* read [more] text into this block */
  269.             nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf);
  270.             if (nread < 0)
  271.             {
  272.                 close(origfd);
  273.                 close(tmpfd);
  274.                 tmpfd = -1;
  275.                 unlink(tmpname);
  276.                 FAIL("Error reading \"%s\"", origname);
  277.             }
  278.  
  279.             /* convert NUL characters to something else */
  280.             for (j = k = inbuf; k < inbuf + nread; k++)
  281.             {
  282.                 if (!this->c[k])
  283.                 {
  284.                     setflag(file, HADNUL);
  285.                     this->c[j++] = 0x80;
  286.                 }
  287. #ifndef CRUNCH
  288.                 else if (*o_beautify && this->c[k] < ' ' && this->c[k] > 0)
  289.                 {
  290.                     if (this->c[k] == '\t'
  291.                      || this->c[k] == '\n'
  292.                      || this->c[k] == '\f')
  293.                     {
  294.                         this->c[j++] = this->c[k];
  295.                     }
  296.                     else if (this->c[k] == '\b')
  297.                     {
  298.                         /* delete '\b', but complain */
  299.                         setflag(file, HADBS);
  300.                     }
  301.                     /* else silently delete control char */
  302.                 }
  303. #endif
  304.                 else
  305.                 {
  306.                     this->c[j++] = this->c[k];
  307.                 }
  308.             }
  309.             inbuf = j;
  310.  
  311.             /* if the buffer is empty, quit */
  312.             if (inbuf == 0)
  313.             {
  314.                 goto FoundEOF;
  315.             }
  316.  
  317. #if MSDOS || TOS
  318. /* BAH! MS text mode read fills inbuf, then compresses eliminating \r
  319.    but leaving garbage at end of buf. The same is true for TURBOC. GB. */
  320.  
  321.             memset(this->c + inbuf, '\0', BLKSIZE - inbuf);
  322. #endif
  323.  
  324.             /* search backward for last newline */
  325.             for (k = inbuf; --k >= 0 && this->c[k] != '\n';)
  326.             {
  327.             }
  328.             if (k++ < 0)
  329.             {
  330.                 if (inbuf >= BLKSIZE - 1)
  331.                 {
  332.                     k = 80;
  333.                 }
  334.                 else
  335.                 {
  336.                     k = inbuf;
  337.                 }
  338.             }
  339.  
  340.             /* allocate next buffer */
  341.             next = blkget(++i);
  342.  
  343.             /* move fragmentary last line to next buffer */
  344.             inbuf -= k;
  345.             for (j = 0; k < BLKSIZE; j++, k++)
  346.             {
  347.                 next->c[j] = this->c[k];
  348.                 this->c[k] = 0;
  349.             }
  350.  
  351.             /* if necessary, add a newline to this buf */
  352.             for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; )
  353.             {
  354.             }
  355.             if (this->c[k] != '\n')
  356.             {
  357.                 setflag(file, ADDEDNL);
  358.                 this->c[k + 1] = '\n';
  359.             }
  360.  
  361.             /* count the lines in this block */
  362.             for (k = 0; k < BLKSIZE && this-